package nl.rainbowsheep.reisorg.rest.service.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import nl.rainbowsheep.reisorg.rest.service.model.Accommodation;
import nl.rainbowsheep.reisorg.rest.service.model.AccommodationHousingBooking;
import nl.rainbowsheep.reisorg.rest.service.model.AccommodationLocalized;
import nl.rainbowsheep.reisorg.rest.service.model.AccommodationType;
import nl.rainbowsheep.reisorg.rest.service.model.City;
import nl.rainbowsheep.reisorg.rest.service.model.Language;
import nl.rainbowsheep.reisorg.rest.service.repository.AccommodationHousingBookingRepository;
import nl.rainbowsheep.reisorg.rest.service.repository.AccommodationRepository;
import nl.rainbowsheep.reisorg.rest.service.viewmodel.AccommodationViewmodel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccommodationService {

    @Autowired
    private AccommodationRepository accommodationRepository;
    @Autowired
    private AccommodationHousingBookingRepository accommodationHousingBookingRepo;
    @Autowired
    private AccommodationTypeService accommodationtypeService;
    @Autowired
    private CityService cityService;
    @Autowired
    private CountryService countryService;
    @Autowired
    private RegionService regionService;
    @Autowired
    private AccommodationHousingService housingService;

    public Accommodation getById(long id) {
        return accommodationRepository.findOne(id);
    }
   
    /**
     * get all Accommodations and put them in a AccommodationViewmodel object.
     *
     * @return collection of all Accommodations in AccommodationViewmodels
     */
    public List<AccommodationViewmodel> getAll() {
        AccommodationViewmodel accommodationViewmodel;
        List<Accommodation> accommodations = accommodationRepository.findAll();
        List<AccommodationViewmodel> accommodationViewmodels = new ArrayList();

        for (Accommodation a : accommodations) {
            accommodationViewmodel = new AccommodationViewmodel();
            accommodationViewmodel.setAccommodationType(accommodationtypeService.findById(a.getAccommodationTypeId()));
            City city = cityService.findById(a.getCityId());
            accommodationViewmodel.setCity(city);
            accommodationViewmodel.setRegion(regionService.getRegionById(city.getRegionId()));
            accommodationViewmodel.setCountry(countryService.getCountryById(a.getCountryId()));

            accommodationViewmodel.setDescription(a.getDescription());
            accommodationViewmodel.setHousenumber(a.getHousenumber());
            accommodationViewmodel.setId(a.getId());
            accommodationViewmodel.setIsActive(a.isIsActive());
            accommodationViewmodel.setLastUpdate(a.getLastUpdate());
            accommodationViewmodel.setPostalCode(a.getPostalCode());
            accommodationViewmodel.setStreet(a.getStreet());
            accommodationViewmodel.setTitle(a.getTitle());
            accommodationViewmodels.add(accommodationViewmodel);
        }
        return accommodationViewmodels;
    }

    /**
     * Method saves Accommodation and Housing from a Booking
     *
     * @param booking
     * @return
     */
    public AccommodationHousingBooking saveBooking(AccommodationHousingBooking booking) {
        return accommodationHousingBookingRepo.save(booking);
    }

    /**
     * Method finds all accommodations that match the AccommodationViewmodel
     * criteria.
     *
     * @param accviewmod
     * @return
     */
    public List<AccommodationViewmodel> findAccommodations(AccommodationViewmodel accviewmod) {

        Long cityId = null;
        if (accviewmod.getCity() != null) {
            cityId = accviewmod.getCity().getId();
        }
        Long countryId = null;
        if (accviewmod.getCountry() != null) {
            countryId = accviewmod.getCountry().getId();
        }
        String title = null;
        title = accviewmod.getTitle();
        List<Accommodation> searchResults = new ArrayList();

        if (cityId != null && countryId != null && title != null) {
            searchResults = accommodationRepository.findByTitleLikeAndCityIdAndCountryIdAndIsActiveAllIgnoreCase(title, cityId, countryId, true);
        } else if (cityId != null && countryId != null) {
            searchResults = accommodationRepository.findByCityIdAndCountryIdAndIsActive(cityId, countryId, true);
        } else if (cityId != null) {
            searchResults = accommodationRepository.findByCityIdAndIsActive(cityId, true);
        } else if (countryId != null) {
            searchResults = accommodationRepository.findByCountryIdAndIsActive(countryId, true);
        } else if (title != null && cityId != null) {
            searchResults = accommodationRepository.findByTitleLikeAndCityIdAndIsActiveAllIgnoreCase(title, cityId, true);
        } else if (title != null && countryId != null) {
            searchResults = accommodationRepository.findByTitleLikeAndCountryIdAndIsActiveAllIgnoreCase(title, countryId, true);
        } else if (title != null) {
            searchResults = accommodationRepository.findByTitleLikeAndIsActiveAllIgnoreCase(title, true);
        }

        AccommodationViewmodel accommodationViewmodel;
        List<AccommodationViewmodel> accommodationViewmodels = new ArrayList();
        
        for (Accommodation a : searchResults) {
            accommodationViewmodel = new AccommodationViewmodel();
            accommodationViewmodel.setAccommodationType(accommodationtypeService.findById(a.getAccommodationTypeId()));
            City city = cityService.findById(a.getCityId());
            accommodationViewmodel.setCity(city);
            accommodationViewmodel.setRegion(regionService.getRegionById(city.getRegionId()));
            accommodationViewmodel.setCountry(countryService.getCountryById(a.getCountryId()));
            accommodationViewmodel.setDescription(a.getDescription());
            accommodationViewmodel.setHousenumber(a.getHousenumber());
            accommodationViewmodel.setId(a.getId());
            accommodationViewmodel.setIsActive(a.isIsActive());
            accommodationViewmodel.setLastUpdate(a.getLastUpdate());
            accommodationViewmodel.setPostalCode(a.getPostalCode());
            accommodationViewmodel.setStreet(a.getStreet());
            accommodationViewmodel.setTitle(a.getTitle());
            accommodationViewmodel.setHousings(housingService.getByAccommodationId(a.getId()));
            accommodationViewmodels.add(accommodationViewmodel);
        }
        return accommodationViewmodels;
    }

    /**
     * Method returns AccommodationViewmodel with specified id
     *
     * @param id
     * @return
     */
    public AccommodationViewmodel findOne(long id) {
        Accommodation a = accommodationRepository.findOne(id);

        AccommodationViewmodel accommodationViewmodel = null;
        if (a != null) {
            accommodationViewmodel = new AccommodationViewmodel();
            accommodationViewmodel.setAccommodationType(accommodationtypeService.findById(a.getAccommodationTypeId()));
            City city = cityService.findById(a.getCityId());
            accommodationViewmodel.setCity(city);
            accommodationViewmodel.setRegion(regionService.getRegionById(city.getRegionId()));
            accommodationViewmodel.setCountry(countryService.getCountryById(a.getCountryId()));
            accommodationViewmodel.setDescription(a.getDescription());
            accommodationViewmodel.setHousenumber(a.getHousenumber());
            accommodationViewmodel.setId(a.getId());
            accommodationViewmodel.setIsActive(a.isIsActive());
            accommodationViewmodel.setLastUpdate(a.getLastUpdate());
            accommodationViewmodel.setPostalCode(a.getPostalCode());
            accommodationViewmodel.setStreet(a.getStreet());
            accommodationViewmodel.setTitle(a.getTitle());

        }
        return accommodationViewmodel;
    }

    /**
     * Convert AccommodationViewmodels to Accommodations so they can be stored
     * in database.
     *
     * @param avmodels
     * @return
     */
    public List<Accommodation> convertAccommodationViewmodels(List<AccommodationViewmodel> avmodels) {
        List<Accommodation> accommodations = new ArrayList();

        for (AccommodationViewmodel avm : avmodels) {
            Accommodation a = new Accommodation();

            a.setAccommodationTypeId(avm.getAccommodationType().getId());
            a.setCityId(avm.getCity().getId());
            a.setCountryId(avm.getCountry().getId());
            a.setDescription(avm.getDescription());
            a.setHousenumber(avm.getHousenumber());
            a.setId(avm.getId());
            a.setIsActive(avm.isIsActive());
            a.setLastUpdate(avm.getLastUpdate());
//            a.setLocale(null);
            a.setPostalCode(avm.getPostalCode());
            a.setStreet(avm.getStreet());
            a.setTitle(avm.getTitle());
            accommodations.add(a);
        }
        return accommodations;
    }

    /**
     * Method checks if given AccommodationType already exists. If so, then no
     * insertion of AccommodationType will be done. If not, there is an
     * insertion of a new AccommodationType.
     *
     * Chose to handle insertion of the data-member 'description' in a separate
     * method because of multilingual fields.
     *
     * @param accommodationViewmodel
     * @return
     */
    public Accommodation save(AccommodationViewmodel accommodationViewmodel) {
        Accommodation a = null;
        if (accommodationViewmodel != null) {
            AccommodationType accommodationType = accommodationtypeService.findByType(accommodationViewmodel.getAccommodationType().getType());
            // if not exists, add to database
            if (accommodationType == null) {
                accommodationType = accommodationtypeService.save(accommodationViewmodel.getAccommodationType());
            }

            a = new Accommodation();
            a.setAccommodationTypeId(accommodationType.getId());
            a.setCityId(accommodationViewmodel.getCity().getId());
            a.setCountryId(accommodationViewmodel.getCountry().getId());
            a.setDescription(accommodationViewmodel.getDescription());
            a.setHousenumber(accommodationViewmodel.getHousenumber());
//            a.setId(accommodationViewmodel.getId());
            a.setIsActive(true);
            a.setLastUpdate(accommodationViewmodel.getLastUpdate());
//        a.setLocale();
            a.setPostalCode(accommodationViewmodel.getPostalCode());
            a.setStreet(accommodationViewmodel.getStreet());
            a.setTitle(accommodationViewmodel.getTitle());
        } else {
            return null;
        }
        
        Accommodation accommodationToCheck = accommodationRepository.findByTitle(a.getTitle());
        Map<Language, AccommodationLocalized> localizedMap = null;
        
        if (accommodationToCheck != null) {
            a.setId(accommodationToCheck.getId());
            if (accommodationToCheck.getLocale() != null) {
                localizedMap = accommodationToCheck.getLocale();
            }
        }
        if (localizedMap == null) {
            localizedMap = new HashMap<Language, AccommodationLocalized>();
        }
        a.setLocale(localizedMap);
        return accommodationRepository.save(a);
    }

}
